2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
27 $Log: Mac\040OS\040Test\040Searcher.c,v $
28 Revision 1.17 2004/06/10 04:37:27 cheshire
29 Add new parameter in mDNS_GetDomains()
31 Revision 1.16 2004/03/12 21:30:25 cheshire
32 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
33 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
35 Revision 1.15 2004/01/24 23:55:15 cheshire
36 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
38 Revision 1.14 2003/11/14 21:27:09 cheshire
39 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
40 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
42 Revision 1.13 2003/08/14 02:19:54 cheshire
43 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
45 Revision 1.12 2003/08/12 19:56:24 cheshire
50 #include <stdio.h> // For printf()
51 #include <Events.h> // For WaitNextEvent()
52 #include <SIOUX.h> // For SIOUXHandleOneEvent()
54 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
55 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
59 OTLIFO serviceinfolist
;
60 Boolean headerPrinted
;
64 typedef struct { ServiceInfo i
; mDNSBool add
; mDNSBool dom
; OTLink link
; } linkedServiceInfo
;
66 // These don't have to be globals, but their memory does need to remain valid for as
67 // long as the search is going on. They are declared as globals here for simplicity.
68 #define RR_CACHE_SIZE 1000
69 static CacheRecord rrcachestorage
[RR_CACHE_SIZE
];
70 static mDNS mDNSStorage
;
71 static mDNS_PlatformSupport PlatformSupportStorage
;
72 static SearcherServices services
;
73 static DNSQuestion browsequestion
, domainquestion
;
75 // PrintServiceInfo prints the service information to standard out
76 // A real application might want to do something else with the information
77 static void PrintServiceInfo(SearcherServices
*services
)
79 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
83 linkedServiceInfo
*ls
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
84 ServiceInfo
*s
= &ls
->i
;
86 if (!services
->headerPrinted
)
88 printf("%-55s Type Domain IP Address Port Info\n", "Name");
89 services
->headerPrinted
= true;
94 char c_dom
[MAX_ESCAPED_DOMAIN_NAME
];
95 ConvertDomainNameToCString(&s
->name
, c_dom
);
96 if (ls
->add
) printf("%-55s available for browsing\n", c_dom
);
97 else printf("%-55s no longer available for browsing\n", c_dom
);
102 domainname type
, domain
;
103 char c_name
[MAX_DOMAIN_LABEL
+1], c_type
[MAX_ESCAPED_DOMAIN_NAME
], c_dom
[MAX_ESCAPED_DOMAIN_NAME
], c_ip
[20];
104 DeconstructServiceName(&s
->name
, &name
, &type
, &domain
);
105 ConvertDomainLabelToCString_unescaped(&name
, c_name
);
106 ConvertDomainNameToCString(&type
, c_type
);
107 ConvertDomainNameToCString(&domain
, c_dom
);
108 sprintf(c_ip
, "%d.%d.%d.%d", s
->ip
.ip
.v4
.b
[0], s
->ip
.ip
.v4
.b
[1], s
->ip
.ip
.v4
.b
[2], s
->ip
.ip
.v4
.b
[3]);
110 printf("%-55s %-16s %-14s ", c_name
, c_type
, c_dom
);
111 if (ls
->add
) printf("%-15s %5d %#s\n", c_ip
, mDNSVal16(s
->port
), s
->TXTinfo
);
112 else printf("Removed\n");
120 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
121 // enqueues a record for PrintServiceInfo() to print.
122 // Note, a browsing application would *not* normally need to get all this information --
123 // all it needs is the name, to display to the user.
124 // Finding out the address, port, and txtinfo should be deferred to the time that the user
125 // actually needs to contact the service to use it.
126 static void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
128 SearcherServices
*services
= (SearcherServices
*)query
->ServiceInfoQueryContext
;
129 linkedServiceInfo
*info
= (linkedServiceInfo
*)(query
->info
);
130 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
132 mDNS_StopResolveService(m
, query
); // For this test code, one answer is sufficient
133 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
138 // When a new named instance of a service is found, FoundInstance() is called.
139 // In this sample code we turn around and immediately issue a query to resolve that service name to
140 // find its address, port, and txtinfo, but a normal browing application would just display the name.
141 static void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
143 #pragma unused (question)
144 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
145 linkedServiceInfo
*info
;
147 debugf("FoundInstance %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
149 if (answer
->rrtype
!= kDNSType_PTR
) return;
150 if (!services
) { debugf("FoundInstance: services is NULL"); return; }
152 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
153 if (!info
) { services
->lostRecords
= true; return; }
155 info
->i
.name
= answer
->rdata
->u
.name
;
156 info
->i
.InterfaceID
= answer
->InterfaceID
;
157 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
158 info
->i
.ip
.ip
.v4
= zeroIPAddr
;
159 info
->i
.port
= zeroIPPort
;
160 info
->add
= AddRecord
;
161 info
->dom
= mDNSfalse
;
163 if (!AddRecord
) // If TTL == 0 we're deleting a service,
164 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
165 else // else we're adding a new service
167 ServiceInfoQuery
*q
= (ServiceInfoQuery
*)OTAllocMem(sizeof(ServiceInfoQuery
));
168 if (!q
) { OTFreeMem(info
); services
->lostRecords
= true; return; }
169 mDNS_StartResolveService(m
, q
, &info
->i
, FoundInstanceInfo
, services
);
173 static void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
176 #pragma unused (question)
177 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
178 linkedServiceInfo
*info
;
180 debugf("FoundDomain %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
182 if (answer
->rrtype
!= kDNSType_PTR
) return;
183 if (!services
) { debugf("FoundDomain: services is NULL"); return; }
185 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
186 if (!info
) { services
->lostRecords
= true; return; }
188 info
->i
.name
= answer
->rdata
->u
.name
;
189 info
->i
.InterfaceID
= answer
->InterfaceID
;
190 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
191 info
->i
.ip
.ip
.v4
= zeroIPAddr
;
192 info
->i
.port
= zeroIPPort
;
193 info
->add
= AddRecord
;
194 info
->dom
= mDNStrue
;
196 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
199 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
200 static Boolean
YieldSomeTime(UInt32 milliseconds
)
202 extern Boolean SIOUXQuitting
;
204 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
205 SIOUXHandleOneEvent(&e
);
206 return(SIOUXQuitting
);
212 Boolean DoneSetup
= false;
215 SIOUXSettings
.asktosaveonclose
= false;
216 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
217 SIOUXSettings
.rows
= 40;
218 SIOUXSettings
.columns
= 132;
220 printf("Multicast DNS Searcher\n\n");
221 printf("This software reports errors using MacsBug breaks,\n");
222 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
223 printf("******************************************************************************\n");
225 err
= InitOpenTransport();
226 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
228 err
= mDNS_Init(&mDNSStorage
, &PlatformSupportStorage
, rrcachestorage
, RR_CACHE_SIZE
,
229 mDNS_Init_DontAdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
230 if (err
) return(err
);
232 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
233 tempmem
= OTAllocMem(0x10000);
234 if (tempmem
) OTFreeMem(tempmem
);
235 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
237 services
.serviceinfolist
.fHead
= NULL
;
238 services
.headerPrinted
= false;
239 services
.lostRecords
= false;
241 while (!YieldSomeTime(35))
243 #if MDNS_ONLYSYSTEMTASK
244 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
245 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
246 extern void mDNSPlatformIdle(mDNS
*const m
);
247 mDNSPlatformIdle(&mDNSStorage
); // Only needed for debugging version
249 if (mDNSStorage
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
251 domainname srvtype
, srvdom
;
253 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
254 MakeDomainNameFromDNSNameString(&srvtype
, "_http._tcp.");
255 MakeDomainNameFromDNSNameString(&srvdom
, "local.");
256 err
= mDNS_StartBrowse(&mDNSStorage
, &browsequestion
, &srvtype
, &srvdom
, mDNSInterface_Any
, FoundInstance
, &services
);
258 err
= mDNS_GetDomains(&mDNSStorage
, &domainquestion
, mDNS_DomainTypeBrowse
, NULL
, mDNSInterface_Any
, FoundDomain
, &services
);
262 if (services
.serviceinfolist
.fHead
)
263 PrintServiceInfo(&services
);
265 if (services
.lostRecords
)
267 services
.lostRecords
= false;
268 printf("**** Warning: Out of memory: Records have been missed.\n");
272 mDNS_StopBrowse(&mDNSStorage
, &browsequestion
);
273 mDNS_Close(&mDNSStorage
);